home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / QuickDraw3D 1.6 SDK / Mac SampleCode New for 1.6 / WorldRayPickSample / Source / WRay_Scene.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-20  |  18.9 KB  |  827 lines  |  [TEXT/CWIE]

  1. /* 
  2.  *    WRay_Scene.c
  3.  *
  4.  *    QuickDraw 3D 1.6 Sample
  5.  *    Robert Dierkes
  6.  *
  7.  *     07/28/98    RDD        Created.
  8.  */
  9.  
  10. /*------------------*/
  11. /*    Include Files    */
  12. /*------------------*/
  13. #include "QD3D.h"
  14. #include "QD3DDrawContext.h"
  15. #include "QD3DCamera.h"
  16. #include "QD3DLight.h"
  17. #include "QD3DGeometry.h"
  18. #include "QD3DGroup.h"
  19. #include "QD3DMath.h"
  20. #include "QD3DRenderer.h"
  21. #include "QD3DShader.h"
  22. #include "QD3DTransform.h"
  23. #include "QD3DView.h"
  24.  
  25. #include "WRay_Error.h"
  26. #include "WRay_Document.h"
  27. #include "WRay_Main.h"
  28. #include "WRay_Memory.h"
  29. #include "WRay_Scene.h"
  30. #include "WRay_System.h"
  31.  
  32. #include <math.h>
  33.  
  34.  
  35. /*------------------*/
  36. /*      Constants        */
  37. /*------------------*/
  38. #define    kDefaultCamLoc        0.0, 0.0, 10.0
  39. #define    kDefaultPtOfInt        0.0, 0.0, 0.0
  40. #define    kDefaultUpVector    0.0, 1.0, 0.0
  41.  
  42.  
  43. /*----------------------*/
  44. /*    Global Declarations    */
  45. /*----------------------*/
  46. static    TQ3CameraObject    gCamera            = NULL;
  47. static    TQ3Boolean        gDoRotation        = kQ3False;
  48. static    float            gRotationAngle    = Q3Math_DegreesToRadians(90.0f);
  49. static    float            gAngleDelta        = 0.0;
  50. static    TRotationSpeed    gRotationSpeed;
  51. static    TQ3Boolean        gShowLines        = kQ3False;
  52.  
  53.  
  54. /*----------------------*/
  55. /*    Local Prototypes    */
  56. /*----------------------*/
  57. static
  58. TQ3DrawContextObject Scene_NewDrawContext(
  59.             WindowPtr        pWindow);
  60. static
  61. TQ3Status Scene_ChangeViewAttributes(
  62.             TQ3ViewObject    view);
  63. static
  64. TQ3Status Scene_NewRenderer(
  65.             TQ3ViewObject    view,
  66.             TQ3ObjectType    rendererType);
  67. static
  68. TQ3CameraObject Scene_NewCamera(
  69.             Rect            *pWindowRect);
  70. static
  71. TQ3GroupObject Scene_NewLights(
  72.             void);
  73. static
  74. TQ3Status    Scene_NewStyles(
  75.             TQ3GroupObject    group);
  76. static
  77. TQ3Status    Scene_NewScene(
  78.             TQ3GroupObject    group);
  79. static
  80. TQ3Status    Scene_NewBoxSides(
  81.             TQ3GroupObject    group,
  82.             TQ3BoundingBox    *pBBox);
  83.  
  84.  
  85. /*
  86.  *    Scene_NewView
  87.  */
  88. TQ3ViewObject     Scene_NewView(
  89.     WindowPtr        pWindow)
  90. {
  91.     TQ3Status                status = kQ3Failure;
  92.     TQ3ViewObject            view;
  93.     TQ3DrawContextObject    drawContext;
  94.     TQ3CameraObject            camera;
  95.     TQ3GroupObject            lights;
  96.  
  97.     view = Q3View_New();
  98.     DEBUG_ASSERT(view != NULL, Scene_NewView);
  99.     if (view == NULL) {
  100.         goto bail;
  101.     }
  102.  
  103.     /* Create and set draw context */
  104.     DEBUG_ASSERT(pWindow != NULL, Scene_NewView);
  105.     if ((drawContext = Scene_NewDrawContext(pWindow)) == NULL) {
  106.         goto bail;
  107.     }
  108.  
  109.     if ((status = Q3View_SetDrawContext(view, drawContext)) == kQ3Failure) {
  110.         goto bail;
  111.     }
  112.     Object_Dispose_NULL(&drawContext);
  113.  
  114.     /* Change view's attributes */
  115.     if ((status = Scene_ChangeViewAttributes(view)) == kQ3Failure) {
  116.         goto bail;
  117.     }
  118.  
  119.     /* Create and set renderer */
  120.     if ((status = Scene_NewRenderer(view, kQ3RendererTypeInteractive)) == kQ3Failure) {
  121.         goto bail;
  122.     }
  123.  
  124.     /* Create and set camera */
  125.     if ((camera = Scene_NewCamera(&pWindow->portRect)) == NULL) {
  126.         goto bail;
  127.     }
  128.  
  129.     if ((status = Q3View_SetCamera(view, camera)) == kQ3Failure) {
  130.         goto bail;
  131.     }
  132.     /* Save reference to camera */
  133.     gCamera = camera;
  134.     Object_Dispose_NULL(&camera);
  135.  
  136.  
  137.     /* Create and set lights */
  138.     if ((lights = Scene_NewLights()) == NULL) {
  139.         goto bail;
  140.     }
  141.  
  142.     if ((status = Q3View_SetLightGroup(view, lights)) == kQ3Failure) {
  143.         goto bail;
  144.     }
  145.     Object_Dispose_NULL(&lights);
  146.  
  147.     return (view);
  148.  
  149. bail:
  150.     return NULL;
  151. }
  152.  
  153.  
  154. /*
  155.  *    Scene_NewDrawContext
  156.  */
  157. static
  158. TQ3DrawContextObject Scene_NewDrawContext(
  159.     WindowPtr        pWindow)
  160. {
  161.     TQ3DrawContextObject        drawContext;
  162.     TQ3DrawContextData            *pDCData;
  163.     TQ3MacDrawContextData        macDrawContextData;
  164.  
  165.     pDCData = &macDrawContextData.drawContextData;
  166.  
  167.     #define    kDefaultClearImageColor        1.0, 0.15, 0.15, 0.15
  168.  
  169.     /* Fill in common draw context data */
  170.     pDCData->clearImageMethod = kQ3ClearMethodWithColor;
  171.     Q3ColorARGB_Set(&pDCData->clearImageColor, kDefaultClearImageColor);
  172.     pDCData->paneState         = kQ3False;
  173.     pDCData->maskState         = kQ3False;
  174.  
  175.  
  176.     /* Mac draw context */
  177.     pDCData->doubleBufferState = kQ3True;
  178.  
  179.     /* This is the window associated with the view */
  180.     DEBUG_ASSERT(pWindow != NULL, Scene_NewDrawContext);
  181.     macDrawContextData.window   = (CGrafPtr) pWindow;
  182.     macDrawContextData.library  = kQ3Mac2DLibraryNone;
  183.     macDrawContextData.viewPort = NULL;
  184.     macDrawContextData.grafPort = NULL;
  185.  
  186.     /* Create draw context and return it, if it’s nil the caller must handle */
  187.     drawContext = Q3MacDrawContext_New(&macDrawContextData);
  188.  
  189.     DEBUG_ASSERT(drawContext != NULL, Scene_NewDrawContext);
  190.  
  191.     #undef    kDefaultClearImageColor
  192.  
  193.     return drawContext;
  194. }
  195.  
  196.  
  197. /*
  198.  *    Scene_ChangeViewAttributes
  199.  */
  200. TQ3Status Scene_ChangeViewAttributes(
  201.     TQ3ViewObject    view)
  202. {
  203.     TQ3Status            status = kQ3Failure;
  204.     TQ3AttributeSet     attributeSet = NULL;
  205.     TQ3ColorRGB            color = { 1.0, 0.0, 0.0 };
  206.  
  207.     status = Q3View_GetDefaultAttributeSet(view, &attributeSet);
  208.     DEBUG_ASSERT(status == kQ3Success, Q3View_GetDefaultAttributeSet);
  209.     DEBUG_ASSERT(attributeSet != NULL, Q3View_GetDefaultAttributeSet);
  210.     if (status == kQ3Failure) {
  211.         return status;
  212.     }
  213.  
  214.     /* Change view's specular color */
  215.     Q3AttributeSet_Add(attributeSet, kQ3AttributeTypeSpecularColor, &color);
  216.  
  217.     status = Q3View_SetDefaultAttributeSet(view, attributeSet);
  218.     DEBUG_ASSERT(status == kQ3Success, Q3View_SetDefaultAttributeSet);
  219.     Object_Dispose_NULL(&attributeSet);
  220.  
  221.     return status;
  222. }
  223.  
  224.  
  225. /*
  226.  *    Scene_NewRenderer
  227.  */
  228. TQ3Status Scene_NewRenderer(
  229.     TQ3ViewObject    view,
  230.     TQ3ObjectType    rendererType)
  231. {
  232.     TQ3Status            status = kQ3Failure;
  233.     TQ3RendererObject    renderer = NULL;
  234.  
  235.     if (view == NULL) {
  236.         ERROR_DEBUG_STR("Scene_NewRenderer: view == NULL.");
  237.         return status;
  238.     }
  239.  
  240.     /* Use the interactive software renderer if present */
  241.     if ((renderer = Q3Renderer_NewFromType(rendererType)) != NULL) {
  242.  
  243.         if ((status = Q3View_SetRenderer(view, renderer)) == kQ3Success) {
  244.             /* Use hardware accelerator for IR if present */
  245.             if (rendererType == kQ3RendererTypeInteractive) {
  246.                 Q3InteractiveRenderer_SetDoubleBufferBypass(renderer, kQ3True);
  247.             } 
  248.         } 
  249.         else {
  250.             ERROR_DEBUG_STR("Scene_NewRenderer: Q3View_SetRenderer failed.");
  251.         }
  252.     }
  253.     else {
  254.         /* Default to wireframe renderer */
  255.         if ((renderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame)) != NULL) {
  256.  
  257.             if ((status = Q3View_SetRenderer(view, renderer)) == kQ3Failure) {
  258.                 ERROR_DEBUG_STR("Scene_NewRenderer: Q3View_SetRenderer(WF) failed.");
  259.             }
  260.         }
  261.     }
  262.  
  263.     Object_Dispose_NULL(&renderer);
  264.  
  265.     return status;
  266. }
  267.  
  268.  
  269. /*
  270.  *    Scene_NewCamera
  271.  */
  272. static
  273. TQ3CameraObject Scene_NewCamera(
  274.     Rect            *pWindowRect)
  275. {
  276.     TQ3ViewAngleAspectCameraData
  277.                         perspectiveData;
  278.     TQ3CameraObject        camera;
  279.     TQ3Point3D             from    = { kDefaultCamLoc };
  280.     TQ3Point3D             to        = { kDefaultPtOfInt };
  281.     TQ3Vector3D         up        = { kDefaultUpVector };
  282.  
  283.     perspectiveData.cameraData.placement.cameraLocation     = from;
  284.     perspectiveData.cameraData.placement.pointOfInterest     = to;
  285.     perspectiveData.cameraData.placement.upVector             = up;
  286.  
  287.     perspectiveData.cameraData.range.hither    = kDefaultHither;
  288.     perspectiveData.cameraData.range.yon     = kDefaultYon;
  289.  
  290.     perspectiveData.cameraData.viewPort.origin.x = -1.0;
  291.     perspectiveData.cameraData.viewPort.origin.y =  1.0;
  292.     perspectiveData.cameraData.viewPort.width    =  2.0;
  293.     perspectiveData.cameraData.viewPort.height   =  2.0;
  294.  
  295.     perspectiveData.fov                = kDefaultFieldOfView;
  296.     perspectiveData.aspectRatioXToY    =
  297.         (float) (pWindowRect->right -  pWindowRect->left) / 
  298.         (float) (pWindowRect->bottom - pWindowRect->top);
  299.  
  300.     camera = Q3ViewAngleAspectCamera_New(&perspectiveData);
  301.     DEBUG_ASSERT(camera != NULL, Scene_NewCamera);
  302.  
  303.     return camera;
  304. }
  305.  
  306.  
  307. /*----------------------------------------------------------------------------------*/
  308.  
  309. /*
  310.  *    Scene_NewLights
  311.  */
  312. static
  313. TQ3GroupObject Scene_NewLights(
  314.     void)
  315. {
  316.     TQ3GroupPosition        groupPosition = NULL;
  317.     TQ3GroupObject            lightGroup = NULL;
  318.     TQ3LightObject            light = NULL;
  319.     TQ3DirectionalLightData    comboLightData;
  320.  
  321.     /* Create light group and add each of the lights into the group */
  322.     lightGroup = Q3LightGroup_New();
  323.     if (lightGroup == NULL)
  324.         goto bail;
  325.  
  326.  
  327.     /* Create ambient light */
  328.     comboLightData.lightData.isOn        = kQ3True;
  329.     comboLightData.lightData.brightness = 0.6f;
  330.     Q3ColorRGB_Set(&comboLightData.lightData.color, 1.0f, 1.0f, 1.0f);
  331.  
  332.     light = Q3AmbientLight_New(&comboLightData.lightData);
  333.     DEBUG_ASSERT(light != NULL, Q3AmbientLight_New);
  334.     if (light == NULL)
  335.         goto bail;
  336.  
  337.     groupPosition = Q3Group_AddObject(lightGroup, light);
  338.     DEBUG_ASSERT(groupPosition != NULL, Q3Group_AddObject);
  339.     if (groupPosition == NULL)
  340.         goto bail;
  341.     Object_Dispose_NULL(&light);
  342.  
  343.  
  344.     /* Create a yellow directional light */
  345.     comboLightData.lightData.brightness    = 0.9f;
  346.     Q3ColorRGB_Set(&comboLightData.lightData.color, 0.9f, 0.9f, 0.0f);
  347.     comboLightData.castsShadows            = kQ3True;
  348.     Q3Vector3D_Set(&comboLightData.direction, 1.0f, -1.0f, -2.0f);
  349.  
  350.     light = Q3DirectionalLight_New(&comboLightData);
  351.     DEBUG_ASSERT(light != NULL, Q3DirectionalLight_New);
  352.     if (light == NULL)
  353.         goto bail;
  354.  
  355.     groupPosition = Q3Group_AddObject(lightGroup, light);
  356.     DEBUG_ASSERT(groupPosition != NULL, Q3Group_AddObject);
  357.     if (groupPosition == NULL)
  358.         goto bail;
  359.     Object_Dispose_NULL(&light);
  360.  
  361.  
  362.     /* Create a magenta directional light */
  363.     comboLightData.lightData.brightness    = 0.9f;
  364.     Q3ColorRGB_Set(&comboLightData.lightData.color, 0.9f, 0.0f, 0.9f);
  365.     comboLightData.castsShadows            = kQ3True;
  366.     Q3Vector3D_Set(&comboLightData.direction, -1.0f, 1.0f, 2.0f);
  367.  
  368.     light = Q3DirectionalLight_New(&comboLightData);
  369.     DEBUG_ASSERT(light != NULL, Q3DirectionalLight_New);
  370.     if (light == NULL)
  371.         goto bail;
  372.  
  373.     groupPosition = Q3Group_AddObject(lightGroup, light);
  374.     DEBUG_ASSERT(groupPosition != NULL, Q3Group_AddObject);
  375.     if (groupPosition == NULL)
  376.         goto bail;
  377.     Object_Dispose_NULL(&light);
  378.  
  379.     return (lightGroup);
  380.  
  381. bail:
  382.     Object_Dispose_NULL(&light);
  383.     Object_Dispose_NULL(&lightGroup);
  384.  
  385.     return (NULL);
  386. }
  387.  
  388.  
  389. /*
  390.  *    Scene_NewModel
  391.  */
  392. TQ3GroupObject Scene_NewModel(
  393.     void)
  394. {
  395.     TQ3Status                status = kQ3Failure;
  396.     TQ3GroupObject            model = NULL;
  397.     TQ3DisplayGroupState    state;
  398.     TQ3ShaderObject            illuminationShader = NULL;
  399.  
  400.     if ((model = Q3OrderedDisplayGroup_New()) != NULL) {
  401.  
  402.         /* Make group inline so state isn't pushed */
  403.         if (Q3DisplayGroup_GetState(model, &state) == kQ3Success) {
  404.             state |= kQ3DisplayGroupStateMaskIsInline;
  405.             Q3DisplayGroup_SetState(model, state);
  406.         }
  407.  
  408.         /* Add shader to model */
  409.         if ((illuminationShader = Q3PhongIllumination_New()) != NULL) {
  410.             Q3Group_AddObject(model, illuminationShader);
  411.             Object_Dispose_NULL(&illuminationShader);
  412.  
  413.             /* Add styles to model */
  414.             if ((status = Scene_NewStyles(model)) == kQ3Success) {
  415.  
  416.                 /* Add geometries to model */
  417.                 status = Scene_NewScene(model);
  418.             }
  419.         }
  420.  
  421.         if (status == kQ3Failure) {
  422.             Object_Dispose_NULL(&model);
  423.         }
  424.     }
  425.  
  426.     return (model);
  427. }
  428.  
  429.  
  430. /*
  431.  *    Scene_NewStyles
  432.  */
  433. static
  434. TQ3Status Scene_NewStyles(
  435.     TQ3GroupObject    group)
  436. {
  437.     TQ3StyleObject        style;
  438.  
  439.     if (group == NULL) {
  440.         ERROR_DEBUG_STR("Scene_NewStyles: group == NULL.");
  441.         return kQ3Failure;
  442.     }
  443.  
  444.     /* Interpolation Style */
  445.     if ((style = Q3InterpolationStyle_New(kQ3InterpolationStyleVertex)) == NULL) {
  446.         ERROR_DEBUG_STR("Scene_NewStyles: Q3InterpolationStyle_New failed.");
  447.         return kQ3Failure;
  448.     }
  449.     Q3Group_AddObject(group, style);
  450.     Object_Dispose_NULL(&style);
  451.  
  452.  
  453.     /* Backfacing Style */
  454.     if ((style = Q3BackfacingStyle_New(kQ3BackfacingStyleBoth)) == NULL) {
  455.         ERROR_DEBUG_STR("Scene_NewStyles: Q3BackfacingStyle_New failed.");
  456.         return kQ3Failure;
  457.     }
  458.     Q3Group_AddObject(group, style);
  459.     Object_Dispose_NULL(&style);
  460.  
  461.  
  462.     /* Fill Style */
  463.     if ((style = Q3FillStyle_New(kQ3FillStyleFilled)) == NULL) {
  464.         ERROR_DEBUG_STR("Scene_NewStyles: Q3FillStyle_New failed.");
  465.         return kQ3Failure;
  466.     }
  467.     Q3Group_AddObject(group, style);
  468.     Object_Dispose_NULL(&style);
  469.  
  470.  
  471.     /* Subdivision Style */
  472.     {
  473.         TQ3SubdivisionStyleData        data;
  474.  
  475.         data.method    = kQ3SubdivisionMethodConstant;
  476.         data.c1        = 9.0f;
  477.         data.c2        = 9.0f;
  478.  
  479.         if ((style = Q3SubdivisionStyle_New(&data)) == NULL) {
  480.             ERROR_DEBUG_STR("Scene_NewStyles: Q3SubdivisionStyle_New failed.");
  481.             return kQ3Failure;
  482.         }
  483.         Q3Group_AddObject(group, style);
  484.         Object_Dispose_NULL(&style);
  485.     }
  486.  
  487.     return kQ3Success;
  488. }
  489.  
  490.  
  491. #pragma mark -
  492.  
  493. /*
  494.  *    Scene_NewScene
  495.  */
  496. static
  497. TQ3Status Scene_NewScene(
  498.     TQ3GroupObject    group)
  499. {
  500.     TQ3Status            status = kQ3Success;
  501.     TQ3BoundingBox        sceneBBox;
  502.     TQ3GeometryObject    geometry = NULL;
  503.     TQ3CylinderData        cylinderData;
  504.     TQ3AttributeSet        attr = NULL;
  505.     unsigned long        rx, cy;
  506.  
  507.     #define    kNumRows            5    /* X */
  508.     #define    kNumColumns            7    /* Y */
  509.  
  510.     #define    kCylHeight            4.0f
  511.     #define    kCylDiameter        (2.0f * kCylRadius)
  512.     #define    kCylGap                (0.9f * kCylRadius)
  513.  
  514.     #define    kSceneWidth            ((kNumColumns * kCylDiameter) + ((kNumColumns-1) * kCylGap))
  515.     #define    kSceneHeight        ((kNumRows    * kCylDiameter) + ((kNumRows-1)    * kCylGap))
  516.     #define    kSceneDepth            kCylHeight
  517.  
  518.     #define    kSceneHalfWidth        (kSceneWidth    / 2.0f)
  519.     #define    kSceneHalfHeight    (kSceneHeight    / 2.0f)
  520.     #define    kSceneHalfDepth        (kSceneDepth    / 2.0f)
  521.  
  522.  
  523.     Scene_SetRotationSpeed(kRotateMedium);
  524.     Scene_SetShowLines(kQ3False);
  525.  
  526.     if (group == NULL) {
  527.         ERROR_DEBUG_STR("Scene_NewScene: group == NULL.");
  528.         return kQ3Failure;
  529.     }
  530.  
  531.     /* Create a 4 sided box */
  532.     Q3Point3D_Set(&sceneBBox.min, -kSceneHalfWidth, -kSceneHalfHeight, -kSceneHalfDepth);
  533.     Q3Point3D_Set(&sceneBBox.max,  kSceneHalfWidth,  kSceneHalfHeight,  kSceneHalfDepth);
  534.     sceneBBox.isEmpty = kQ3False;
  535.  
  536.     if (Scene_NewBoxSides(group, &sceneBBox) == kQ3Failure) {
  537.         return kQ3Failure;
  538.     }
  539.  
  540.     /* Create cylinders inside box */
  541.     for (rx = 0; rx < kNumColumns; rx++) {
  542.         for (cy = 0; cy < kNumRows; cy++) {
  543.  
  544.             /* Skip middle geometry */
  545.             if ((rx == (kNumColumns / 2))  &&  (cy == (kNumRows / 2))) {
  546.                 continue;
  547.             }
  548.             /* Every other geometry */
  549.             if ((rx + cy) & 1) {
  550.                 continue;
  551.             }
  552.  
  553.             /* Cylinder is parallel to z-axis */
  554.             Q3Point3D_Set(&cylinderData.origin,
  555.                 (((float) rx) * (kCylDiameter + kCylGap)) + kCylRadius - kSceneHalfWidth,
  556.                 (((float) cy) * (kCylDiameter + kCylGap)) + kCylRadius - kSceneHalfHeight,
  557.                 -kSceneHalfDepth);
  558.  
  559.             Q3Vector3D_Set(&cylinderData.orientation,    0.0,        0.0,        kCylHeight);
  560.             Q3Vector3D_Set(&cylinderData.majorRadius,    kCylRadius,    0.0,        0.0);
  561.             Q3Vector3D_Set(&cylinderData.minorRadius,    0.0,        kCylRadius,    0.0);
  562.  
  563.             cylinderData.uMin = cylinderData.vMin = 0.0f;
  564.             cylinderData.uMax = cylinderData.vMax = 1.0f;
  565.             cylinderData.caps = kQ3EndCapMaskTop | kQ3EndCapMaskBottom;
  566.  
  567.             cylinderData.interiorAttributeSet    = NULL;
  568.             cylinderData.topAttributeSet        = NULL;
  569.             cylinderData.faceAttributeSet        = NULL;
  570.             cylinderData.bottomAttributeSet        = NULL;
  571.             cylinderData.cylinderAttributeSet    = NULL;
  572.  
  573.             attr = Q3AttributeSet_New();
  574.             if (attr != NULL) {
  575.                 TQ3ColorRGB        rgbColor;
  576.  
  577.                 Q3ColorRGB_Set(&rgbColor,
  578.                                 0.0,
  579.                                 (float) (kNumColumns - rx) / kNumColumns,
  580.                                 (float) cy / kNumRows);
  581.                 Q3AttributeSet_Add(attr, kQ3AttributeTypeDiffuseColor, &rgbColor);
  582.             }
  583.             cylinderData.cylinderAttributeSet = attr;
  584.  
  585.             geometry = Q3Cylinder_New(&cylinderData);
  586.             if (geometry == NULL) {
  587.                 status = kQ3Failure;
  588.                 break;
  589.             }
  590.  
  591.             Object_Dispose_NULL(&attr);
  592.  
  593.             Q3Group_AddObject(group, geometry);
  594.             Object_Dispose_NULL(&geometry);
  595.         }
  596.     }
  597.  
  598.     Object_Dispose_NULL(&attr);
  599.     Object_Dispose_NULL(&geometry);
  600.  
  601.     return status;
  602. }
  603.  
  604.  
  605. static
  606. TQ3Status Scene_NewBoxSides(
  607.     TQ3GroupObject    group,
  608.     TQ3BoundingBox    *pBBox)
  609. {
  610.     #define    kMaxPolygons    4
  611.     #define    kMaxPolyVerts    4
  612.     #define    kOutsetScale    0.15f
  613.  
  614.     TQ3Status            status   = kQ3Success;
  615.     TQ3GeometryObject    geometry = NULL;
  616.     TQ3PolygonData        polyData;
  617.     TQ3Vertex3D            vertices[kMaxPolyVerts],
  618.                         *pVertex;
  619.     TQ3Point3D            min, max;
  620.     unsigned long        side;
  621.     TQ3AttributeSet        attr = NULL;
  622.     float                boxOutset;
  623.  
  624.     min = pBBox->min;
  625.     max = pBBox->max;
  626.  
  627.     boxOutset = (max.x - min.x) * kOutsetScale;
  628.     min.x -= boxOutset;    max.x += boxOutset;
  629.  
  630.     boxOutset = (max.y - min.y) * kOutsetScale;
  631.     min.y -= boxOutset;    max.y += boxOutset;
  632.  
  633.     boxOutset = (max.z - min.z) * kOutsetScale;
  634.     min.z -= boxOutset;    max.z += boxOutset;
  635.  
  636.     polyData.numVertices = kMaxPolyVerts;
  637.     polyData.vertices     = vertices;
  638.  
  639.     pVertex = polyData.vertices;
  640.  
  641.     vertices[0].attributeSet =
  642.     vertices[1].attributeSet =
  643.     vertices[2].attributeSet =
  644.     vertices[3].attributeSet = NULL;
  645.  
  646.     for (side = 0; side < kMaxPolygons; side++) {
  647.  
  648.         attr = Q3AttributeSet_New();
  649.         if (attr != NULL) {
  650.             TQ3ColorRGB        rgbColor;
  651.  
  652.             Q3ColorRGB_Set(&rgbColor, 0.0, 0.5, 0.5);
  653.             Q3AttributeSet_Add(attr, kQ3AttributeTypeDiffuseColor, &rgbColor);
  654.         }
  655.         polyData.polygonAttributeSet = attr;
  656.  
  657.         switch (side) {
  658.         case 0:
  659.             Q3Point3D_Set(&pVertex[0].point, min.x, min.y, min.z);
  660.             Q3Point3D_Set(&pVertex[1].point, min.x, min.y, max.z);
  661.             Q3Point3D_Set(&pVertex[2].point, max.x, min.y, max.z);
  662.             Q3Point3D_Set(&pVertex[3].point, max.x, min.y, min.z);
  663.             break;
  664.  
  665.         case 1:
  666.             Q3Point3D_Set(&pVertex[0].point, max.x, min.y, min.z);
  667.             Q3Point3D_Set(&pVertex[1].point, max.x, min.y, max.z);
  668.             Q3Point3D_Set(&pVertex[2].point, max.x, max.y, max.z);
  669.             Q3Point3D_Set(&pVertex[3].point, max.x, max.y, min.z);
  670.             break;
  671.  
  672.         case 2:
  673.             Q3Point3D_Set(&pVertex[0].point, min.x, max.y, min.z);
  674.             Q3Point3D_Set(&pVertex[1].point, max.x, max.y, min.z);
  675.             Q3Point3D_Set(&pVertex[2].point, max.x, max.y, max.z);
  676.             Q3Point3D_Set(&pVertex[3].point, min.x, max.y, max.z);
  677.             break;
  678.  
  679.         case 3:
  680.             Q3Point3D_Set(&pVertex[0].point, min.x, min.y, min.z);
  681.             Q3Point3D_Set(&pVertex[1].point, min.x, max.y, min.z);
  682.             Q3Point3D_Set(&pVertex[2].point, min.x, max.y, max.z);
  683.             Q3Point3D_Set(&pVertex[3].point, min.x, min.y, max.z);
  684.             break;
  685.         }
  686.  
  687.         geometry = Q3Polygon_New(&polyData);
  688.         Object_Dispose_NULL(&polyData.polygonAttributeSet);
  689.         if (geometry == NULL) {
  690.             return kQ3Failure;
  691.         }
  692.  
  693.         Q3Group_AddObject(group, geometry);
  694.         Object_Dispose_NULL(&geometry);
  695.     }
  696.  
  697.     return kQ3Success;
  698. }
  699.  
  700.  
  701. #pragma mark -
  702.  
  703. /*
  704.  *    Scene_IsRotating
  705.  */
  706. TQ3Boolean Scene_IsRotating(
  707.     void)
  708. {
  709.     return gDoRotation;
  710. }
  711.  
  712.  
  713. /*
  714.  *    Scene_SetIsRotating
  715.  */
  716. TQ3Boolean Scene_SetIsRotating(
  717.     TQ3Boolean        newIsRotating)
  718. {
  719.     TQ3Boolean    oldIsRotating = gDoRotation;
  720.  
  721.     gDoRotation = newIsRotating;
  722.  
  723.     return oldIsRotating;
  724. }
  725.  
  726.  
  727. #pragma mark -
  728.  
  729. /*
  730.  *    Scene_GetRotationSpeed
  731.  */
  732. TRotationSpeed Scene_GetRotationSpeed(
  733.     void)
  734. {
  735.     return gRotationSpeed;
  736. }
  737.  
  738.  
  739. /*
  740.  *    Scene_SetRotationSpeed
  741.  */
  742. TQ3Boolean Scene_SetRotationSpeed(
  743.     TRotationSpeed    newRotationSpeed)
  744. {
  745.     switch (newRotationSpeed) {
  746.     case kRotateSlow:
  747.         gAngleDelta    = Q3Math_DegreesToRadians(0.05f);
  748.         break;
  749.  
  750.     case kRotateMedium:
  751.         gAngleDelta    = Q3Math_DegreesToRadians(1.0f);
  752.         break;
  753.  
  754.     case kRotateFast:
  755.         gAngleDelta    = Q3Math_DegreesToRadians(4.0f);
  756.         break;
  757.  
  758.     default:
  759.         return kQ3False;
  760.     }
  761.  
  762.     gRotationSpeed = newRotationSpeed;
  763.  
  764.     return kQ3True;
  765. }
  766.  
  767.  
  768. #pragma mark -
  769.  
  770. /*
  771.  *    Scene_Rotate
  772.  *
  773.  *    Global:
  774.  *        gCamera
  775.  */
  776. TQ3Status Scene_Rotate(
  777.     void)
  778. {
  779.     TQ3Status            status = kQ3Failure;
  780.     TQ3CameraPlacement    placement;
  781.     float                cameraDist;
  782.  
  783.     if (gDoRotation) {
  784.         gRotationAngle += gAngleDelta;
  785.  
  786.         status = Q3Camera_GetPlacement(gCamera, &placement);
  787.         DEBUG_ASSERT(status == kQ3Success, Q3Camera_GetPlacement);
  788.  
  789.         cameraDist = Q3Point3D_Distance(&placement.cameraLocation, &placement.pointOfInterest);
  790.  
  791.         /* Assumes pointOfInterest is at origin any pointOfInterest.y is 0 */
  792.         placement.cameraLocation.x = cos(gRotationAngle) * cameraDist;
  793.         placement.cameraLocation.z = sin(gRotationAngle) * cameraDist;
  794.  
  795.         status = Q3Camera_SetPlacement(gCamera, &placement);
  796.         DEBUG_ASSERT(status == kQ3Success, Q3Camera_SetPlacement);
  797.     }
  798.  
  799.     return status;
  800. }
  801.  
  802.  
  803. #pragma mark -
  804.  
  805. /*
  806.  *    Scene_GetShowLines
  807.  */
  808. TQ3Boolean Scene_GetShowLines(
  809.     void)
  810. {
  811.     return gShowLines;
  812. }
  813.  
  814.  
  815. /*
  816.  *    Scene_SetShowLines
  817.  */
  818. TQ3Boolean Scene_SetShowLines(
  819.     TQ3Boolean        newShowLines)
  820. {
  821.     TQ3Boolean    oldShowLines = gShowLines;
  822.  
  823.     gShowLines = newShowLines;
  824.  
  825.     return oldShowLines;
  826. }
  827.